package com.ug.common.ratelimit;

import cn.hutool.core.util.StrUtil;
import com.ug.common.enums.ErrorCode;
import com.ug.common.exception.SystemException;
import com.ug.common.utils.IpUtils;
import com.ug.common.utils.RequestHolder;
import com.ug.common.utils.SecurityUtil;

import java.lang.annotation.*;

/**
 * @Author LY
 * @create 2024/8/6 14:40
 * @Description 限流注解
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RateLimit {

    /**
     * 限流key
     */
    String key() default "None";

    /**
     * 限流时间,单位秒
     */
    int time() default 60;

    /**
     * 限流次数
     */
    int maxCount() default 100;

    /**
     * 限流条件类型
     */
    LimitType limitType() default LimitType.GLOBAL;

    /**
     * 限流使用的缓存类型
     */
    RateType rateType() default RateType.GUAVA;


    enum LimitType {

        /**
         * 默认策略全局限流  不区分IP和用户
         */
        GLOBAL{
            @Override
            public String generateCombinedKey(RateLimit rateLimiter) {
                return rateLimiter.key() + this.name();
            }
        },

        /**
         * 根据请求者IP进行限流
         */
        IP {
            @Override
            public String generateCombinedKey(RateLimit rateLimiter) {
                String clientIP = IpUtils.getIpAddress(RequestHolder.getHttpServletRequest());
                return rateLimiter.key() + clientIP;
            }
        },

        /**
         * 按Web用户限流
         */
        SYSTEM_WEB {
            @Override
            public String generateCombinedKey(RateLimit rateLimiter) {
                String username = SecurityUtil.getCurrentUsername();
                if (StrUtil.isEmpty(username)) {
                    throw new SystemException(ErrorCode.COMMON_NO_AUTHORIZATION);
                }
                return rateLimiter.key() + username;
            }
        };

        public abstract String generateCombinedKey(RateLimit rateLimiter);
    }

    enum RateType {

        /**
         * 使用redis做限流
         */
        REDIS,

        /**
         * 使用guava做限流
         */
        GUAVA
    }
}
